# 原型链图解:__proto__与prototype的区别
在JavaScript的世界里,原型链(prototype chain)是一个核心概念,也是理解对象继承机制的关键。今天我们就来深入剖析`__proto__`和`prototype`这两个容易混淆的属性,并用图解的方式让你彻底理解它们的区别和联系。
## 一、基础概念回顾
### 1. 构造函数与实例对象
```javascript
function Person(name) {
this.name = name;
}
const person = new Person('张三');
```
在这个例子中:
- `Person`是构造函数
- `person`是实例对象
### 2. prototype属性
每个**函数**都有一个`prototype`属性(箭头函数除外),它指向一个对象,这个对象就是该函数的原型对象。
```javascript
console.log(Person.prototype); // 原型对象
```
## 二、__proto__详解
### 1. 什么是__proto__
`__proto__`是每个JavaScript对象(包括函数对象)都有的一个属性,它指向该对象的原型。
```javascript
console.log(person.__proto__ === Person.prototype); // true
```
### 2. __proto__的查找路径
当我们访问一个对象的属性时,JavaScript会:
1. 先在对象自身查找
2. 如果没有找到,就沿着`__proto__`向上查找
3. 直到找到Object.prototype为止(最终为null)
这就是所谓的**原型链**。
## 三、prototype详解
### 1. 什么是prototype
`prototype`是函数特有的属性,它指向一个对象,这个对象包含应该由特定类型的所有实例共享的属性和方法。
```javascript
Person.prototype.sayHello = function() {
console.log(`你好,我是${this.name}`);
};
person.sayHello(); // "你好,我是张三"
```
### 2. 原型对象的结构
原型对象本身也是一个对象,因此它也有自己的`__proto__`:
```javascript
console.log(Person.prototype.__proto__ === Object.prototype); // true
```
## 四、图解原型链关系
让我们用一张图来清晰展示这些关系:
```
实例对象(person)
|
| __proto__
v
构造函数(Person)的原型对象(Person.prototype)
|
| __proto__
v
Object的原型对象(Object.prototype)
|
| __proto__
v
null
```
同时,构造函数本身也有原型链:
```
构造函数(Person)
|
| __proto__
v
Function的原型对象(Function.prototype)
|
| __proto__
v
Object的原型对象(Object.prototype)
|
| __proto__
v
null
```
## 五、常见误区澄清
1. **函数同时有prototype和__proto__属性**
- `prototype`用于构造函数创建实例时使用
- `__proto__`则指向Function.prototype(因为函数也是对象)
2. **只有函数有prototype**
- 普通对象是没有prototype属性的
- 例如:`person.prototype`是undefined
3. **__proto__不是标准属性**
- 虽然被广泛支持,但更推荐使用`Object.getPrototypeOf()`方法
## 六、实际应用案例
### 1. 实现继承
```javascript
function Parent() {}
function Child() {}
// 设置原型链继承
Child.prototype = new Parent();
Child.prototype.constructor = Child;
const child = new Child();
console.log(child instanceof Parent); // true
```
### 2. 属性屏蔽
```javascript
function Foo() {}
Foo.prototype.x = 1;
const obj = new Foo();
console.log(obj.x); // 1
obj.x = 2; // 在实例上创建属性,屏蔽原型上的属性
console.log(obj.x); // 2
console.log(Foo.prototype.x); // 1
```
## 七、ES6 class语法糖的原型关系
class语法只是原型继承的语法糖:
```javascript
class Person {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, ${this.name}`);
}
}
typeof Person; // "function"
Person.prototype.sayHello; // function
```
## 总结
- `prototype`是函数特有的属性,指向原型对象
- `__proto__`是每个对象都有的属性,指向其原型
- 原型链是通过`__proto__`链接起来的查找机制
- 构造函数、原型对象和实例之间形成一个三角关系
理解原型链是掌握JavaScript面向对象编程的关键,希望这篇文章能帮助你理清这些概念。建议配合实际代码和图解反复练习,才能真正掌握原型继承的精髓。